home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / DirectX SDK / DXSDK / samples / Multimedia / DirectMusic / MusicTool / echotool.cpp < prev    next >
C/C++ Source or Header  |  2001-10-31  |  9KB  |  294 lines

  1. //-----------------------------------------------------------------------------
  2. // File: EchoTool.cpp
  3. //
  4. // Desc: Implements an object based on IDirectMusicTool
  5. //       that provides echoing effects.
  6. //
  7. // Copyright (c) 1998-2001 Microsoft Corporation. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #include <dmusici.h>
  10. #include "EchoTool.h"
  11.  
  12.  
  13.  
  14.  
  15. //-----------------------------------------------------------------------------
  16. // Name: CEchoTool::CEchoTool()
  17. // Desc: 
  18. //-----------------------------------------------------------------------------
  19. CEchoTool::CEchoTool()
  20. {
  21.     m_cRef = 1;                 // Set to 1 so one call to Release() will free this
  22.     m_dwEchoNum = 3;            // Default to 3 echoes per note
  23.     m_mtDelay = DMUS_PPQ / 2;   // Default to 8th note echoes
  24.     InitializeCriticalSection(&m_CrSec);
  25. }
  26.  
  27.  
  28.  
  29.  
  30. //-----------------------------------------------------------------------------
  31. // Name: CEchoTool::~CEchoTool()
  32. // Desc: 
  33. //-----------------------------------------------------------------------------
  34. CEchoTool::~CEchoTool()
  35. {
  36.     DeleteCriticalSection(&m_CrSec);
  37. }
  38.  
  39.  
  40.  
  41.  
  42. //-----------------------------------------------------------------------------
  43. // Name: CEchoTool::QueryInterface()
  44. // Desc: 
  45. //-----------------------------------------------------------------------------
  46. STDMETHODIMP CEchoTool::QueryInterface(const IID &iid, void **ppv)
  47. {
  48.     if (iid == IID_IUnknown || iid == IID_IDirectMusicTool)
  49.     {
  50.         *ppv = static_cast<IDirectMusicTool*>(this);
  51.     } 
  52.     else
  53.     {
  54.         *ppv = NULL;
  55.         return E_NOINTERFACE;
  56.     }
  57.     
  58.     reinterpret_cast<IUnknown*>(this)->AddRef();
  59.     return S_OK;
  60. }
  61.  
  62.  
  63.  
  64.  
  65. //-----------------------------------------------------------------------------
  66. // Name: CEchoTool::AddRef()
  67. // Desc: 
  68. //-----------------------------------------------------------------------------
  69. STDMETHODIMP_(ULONG) CEchoTool::AddRef()
  70. {
  71.     return InterlockedIncrement(&m_cRef);
  72. }
  73.  
  74.  
  75.  
  76.  
  77. //-----------------------------------------------------------------------------
  78. // Name: CEchoTool::Release()
  79. // Desc: 
  80. //-----------------------------------------------------------------------------
  81. STDMETHODIMP_(ULONG) CEchoTool::Release()
  82. {
  83.     if( 0 == InterlockedDecrement(&m_cRef) )
  84.     {
  85.         delete this;
  86.         return 0;
  87.     }
  88.  
  89.     return m_cRef;
  90. }
  91.  
  92.  
  93.  
  94.  
  95. //-----------------------------------------------------------------------------
  96. // Name: CEchoTool::Init()
  97. // Desc: 
  98. //-----------------------------------------------------------------------------
  99. HRESULT STDMETHODCALLTYPE CEchoTool::Init( IDirectMusicGraph* pGraph )
  100. {
  101.     // This tool has no need to do any type of initialization.
  102.     return E_NOTIMPL;
  103. }
  104.  
  105.  
  106.  
  107.  
  108. //-----------------------------------------------------------------------------
  109. // Name: CEchoTool::GetMsgDeliveryType()
  110. // Desc: 
  111. //-----------------------------------------------------------------------------
  112. HRESULT STDMETHODCALLTYPE CEchoTool::GetMsgDeliveryType( DWORD* pdwDeliveryType )
  113. {
  114.     // This tool wants messages immediately.
  115.     // This is the default, so returning E_NOTIMPL
  116.     // would work. The other method is to specifically
  117.     // set *pdwDeliveryType to the delivery type, DMUS_PMSGF_TOOL_IMMEDIATE,
  118.     // DMUS_PMSGF_TOOL_QUEUE, or DMUS_PMSGF_TOOL_ATTIME.
  119.     
  120.     *pdwDeliveryType = DMUS_PMSGF_TOOL_IMMEDIATE;
  121.     return S_OK;
  122. }
  123.  
  124.  
  125.  
  126.  
  127. //-----------------------------------------------------------------------------
  128. // Name: CEchoTool::GetMediaTypeArraySize()
  129. // Desc: 
  130. //-----------------------------------------------------------------------------
  131. HRESULT STDMETHODCALLTYPE CEchoTool::GetMediaTypeArraySize( DWORD* pdwNumElements )
  132. {
  133.     // This tool only wants note messages, patch messages, sysex, and MIDI messages, so set
  134.     // *pdwNumElements to 4.
  135.     
  136.     *pdwNumElements = 4;
  137.     return S_OK;
  138. }
  139.  
  140.  
  141.  
  142.  
  143. //-----------------------------------------------------------------------------
  144. // Name: CEchoTool::GetMediaTypes()
  145. // Desc: 
  146. //-----------------------------------------------------------------------------
  147. HRESULT STDMETHODCALLTYPE CEchoTool::GetMediaTypes( DWORD** padwMediaTypes, 
  148.                                                     DWORD dwNumElements )
  149. {
  150.     // Fill in the array padwMediaTypes with the type of
  151.     // messages this tool wants to process. In this case,
  152.     // dwNumElements will be 3, since that is what this
  153.     // tool returns from GetMediaTypeArraySize().
  154.     
  155.     if( dwNumElements == 4 )
  156.     {
  157.         // Set the elements in the array to DMUS_PMSGT_NOTE,
  158.         // DMUS_PMSGT_MIDI, and DMUS_PMSGT_PATCH
  159.         (*padwMediaTypes)[0] = DMUS_PMSGT_NOTE;
  160.         (*padwMediaTypes)[1] = DMUS_PMSGT_MIDI;
  161.         (*padwMediaTypes)[2] = DMUS_PMSGT_PATCH;
  162.         (*padwMediaTypes)[3] = DMUS_PMSGT_SYSEX;
  163.         return S_OK;
  164.     }
  165.     else
  166.     {
  167.         // This should never happen
  168.         return E_FAIL;
  169.     }
  170. }
  171.  
  172.  
  173.  
  174.  
  175. //-----------------------------------------------------------------------------
  176. // Name: CEchoTool::ProcessPMsg()
  177. // Desc: 
  178. //-----------------------------------------------------------------------------
  179. HRESULT STDMETHODCALLTYPE CEchoTool::ProcessPMsg( IDirectMusicPerformance* pPerf, 
  180.                                                   DMUS_PMSG* pPMsg )
  181. {
  182.     DWORD dwCount;
  183.     DWORD dwEchoNum;
  184.     MUSIC_TIME mtDelay;
  185.     
  186.     // SetEchoNum() and SetDelay() use these member variables,
  187.     // so use a critical section to make them thread-safe.
  188.     EnterCriticalSection(&m_CrSec);
  189.     dwEchoNum = m_dwEchoNum;
  190.     mtDelay = m_mtDelay;
  191.     LeaveCriticalSection(&m_CrSec);
  192.     
  193.     // Returning S_FREE frees the message. If StampPMsg()
  194.     // fails, there is no destination for this message so
  195.     // free it.
  196.     if(( NULL == pPMsg->pGraph ) ||
  197.         FAILED(pPMsg->pGraph->StampPMsg(pPMsg)))
  198.     {
  199.         return DMUS_S_FREE;
  200.     }
  201.  
  202.   
  203.     // The Tool is set up to only receive messages of types
  204.     // DMUS_PMSGT_NOTE, DMUS_PMSGT_MIDI, DMUS_PMSGT_SYSEX, or DMUS_PMSGT_PATCH
  205.     // We use the DX8 ClonePMsg method to make a copy of the pmsg and
  206.     // send it to a pchannel in the next pchannel group. 
  207.     // If it's a note, we also doctor the velocity.
  208.     IDirectMusicPerformance8 *pPerf8;
  209.     if (SUCCEEDED(pPerf->QueryInterface(IID_IDirectMusicPerformance8,(void **)&pPerf8)))
  210.     {
  211.         for( dwCount = 1; dwCount <= dwEchoNum; dwCount++ )
  212.         {
  213.             DMUS_PMSG *pClone;
  214.             if( SUCCEEDED( pPerf8->ClonePMsg( pPMsg,&pClone)))
  215.             {
  216.                 // Add to the time of the echoed note
  217.                 pClone->mtTime += (dwCount * mtDelay);
  218.                 if (pPMsg->dwType == DMUS_PMSGT_NOTE )
  219.                 {
  220.                     DMUS_NOTE_PMSG *pNote = (DMUS_NOTE_PMSG*)pPMsg;
  221.                     DMUS_NOTE_PMSG *pCloneNote = (DMUS_NOTE_PMSG*)pClone;
  222.                     // Reduce the volume of the echoed note
  223.                     // percentage of reduction in velocity increases with each echo
  224.                     pCloneNote->bVelocity = (BYTE) (pNote->bVelocity - 
  225.                         ((pNote->bVelocity * (dwCount * 15))/100));
  226.                 }
  227.                 // Set the note so only MUSIC_TIME is valid.
  228.                 // REFERENCE_TIME will be recomputed inside
  229.                 // SendPMsg()
  230.                 pClone->dwFlags = DMUS_PMSGF_MUSICTIME;
  231.                 pClone->dwPChannel = pPMsg->dwPChannel + 
  232.                     (16*dwCount);
  233.                 // Queue the echoed PMsg
  234.                 pPerf->SendPMsg(pClone );
  235.             }
  236.         }
  237.         pPerf8->Release();
  238.     }
  239.  
  240.  
  241.     // Return DMUS_S_REQUEUE so the original message is requeued
  242.     return DMUS_S_REQUEUE;
  243. }
  244.  
  245.  
  246.  
  247.  
  248. //-----------------------------------------------------------------------------
  249. // Name: CEchoTool::Flush()
  250. // Desc: 
  251. //-----------------------------------------------------------------------------
  252. HRESULT STDMETHODCALLTYPE CEchoTool::Flush( IDirectMusicPerformance* pPerf, 
  253.                                             DMUS_PMSG* pDMUS_PMSG,
  254.                                             REFERENCE_TIME rt)
  255. {
  256.     // This tool does not need to flush.
  257.     return E_NOTIMPL;
  258. }
  259.  
  260.  
  261.  
  262.  
  263. //-----------------------------------------------------------------------------
  264. // Name: CEchoTool::SetEchoNum()
  265. // Desc: 
  266. //-----------------------------------------------------------------------------
  267. void CEchoTool::SetEchoNum( DWORD dwEchoNum )
  268. {
  269.     // ProcessPMsg() uses m_dwEchoNum, so use a critical
  270.     // section to make it thread-safe.
  271.     if( dwEchoNum <= MAX_ECHOES )
  272.     {
  273.         EnterCriticalSection(&m_CrSec);
  274.         m_dwEchoNum = dwEchoNum;
  275.         LeaveCriticalSection(&m_CrSec);
  276.     }
  277. }
  278.  
  279.  
  280.  
  281.  
  282. //-----------------------------------------------------------------------------
  283. // Name: CEchoTool::SetDelay()
  284. // Desc: 
  285. //-----------------------------------------------------------------------------
  286. void CEchoTool::SetDelay( MUSIC_TIME mtDelay )
  287. {
  288.     // ProcessPMsg() uses m_mtDelay, so use a critical
  289.     // section to make it thread-safe.
  290.     EnterCriticalSection(&m_CrSec);
  291.     m_mtDelay = mtDelay;
  292.     LeaveCriticalSection(&m_CrSec);
  293. }
  294.